package ua.edu.nuos.jeetraining2012.cms.util.template.homework;

import org.slf4j.Logger;
import ua.edu.nuos.jeetraining2012.cms.dto.HomeWorkDTO;
import ua.edu.nuos.jeetraining2012.cms.entity.CourseEntity;
import ua.edu.nuos.jeetraining2012.cms.entity.CourseMaterialEntity;
import ua.edu.nuos.jeetraining2012.cms.entity.UserEntity;
import ua.edu.nuos.jeetraining2012.cms.service.Course;
import ua.edu.nuos.jeetraining2012.cms.service.HomeWork;
import ua.edu.nuos.jeetraining2012.cms.service.Material;
import ua.edu.nuos.jeetraining2012.cms.service.exception.ServiceException;
import ua.edu.nuos.jeetraining2012.cms.util.LocaleWrapper;
import ua.edu.nuos.jeetraining2012.cms.util.template.layout.DefaultLayoutTemplate;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.text.MessageFormat;
import java.util.*;

/**
 * @author Victor N. Ganichev victor.ganichev@gmail.com
 * @version 1.0 Date: 26.06.13 Time: 13:30
 * @since 1.0
 */
public class DefaultHomeWorkTemplate extends DefaultLayoutTemplate {

    /** Define course title. */
    protected String courseTitle;

    /** Define course start date. */
    protected Date courseStartDate;

    /** Define course finish date. */
    protected Date courseFinishDate;

    /** Define Course service */
    protected Course courseService;

    /** Define service for HomeWork. */
    protected HomeWork homeWorkService;

    /** Define HW finish date. */
    protected Date homeWorkFinishDate;

    /** Define HW max possible scores */
    protected int homeWorkMaxScore = 0;

    /** Define student achieved scores. */
    protected int studentScore = 0;

    /** Set true, when HW is done. */
    protected boolean isDone = false;

    /** Define list of Homework */
    protected List<HomeWorkDTO> hwList;

    /** Define service for Material. */
    protected Material materialService;

    protected List<CourseMaterialEntity> materialTitles;

    /** Define UserEntity. */
    protected UserEntity userEntity;

    /** Define Logger */
    final private static Logger logger = org.slf4j.LoggerFactory.getLogger(DefaultHomeWorkTemplate.class);

    // Constructors
    /** Default constructor */
    public DefaultHomeWorkTemplate() {
        super();
        logger.debug("DefaultHomeWorkTemplate invocation.");
        logger.debug("Trying to inject service layers.");
        try {
            logger.debug("Trying to inject service class");
            InitialContext ic = new InitialContext();

            homeWorkService = (HomeWork) ic.lookup("java:module/HomeWork");
            logger.debug("Homework service injected: {}", homeWorkService);

            courseService = (Course) ic.lookup("java:module/Course");
            logger.debug("Course service injected: {}", courseService);

            materialService = (Material) ic.lookup("java:module/Material");
            logger.debug("Material service injected: {}", materialService);
        } catch (NamingException e) {
            logger.error("Can't get instance of InitialContext. Got NamingException with message {} and \nTrace:\n {}",
                    e.getMessage(), e.getStackTrace());
        }
        if (subject != null && subject.isAuthenticated()) {
            userEntity = (UserEntity) subject.getSession().getAttribute("user");
        }
    }

    // Getters & Setters
    public HomeWork getHomeWorkService() {
        return homeWorkService;
    }

    public void setHomeWorkService(HomeWork homeWorkService) {
        this.homeWorkService = homeWorkService;
    }

    public String getCourseTitle() {
        return courseTitle;
    }

    public void setCourseTitle(String courseTitle) {
        this.courseTitle = courseTitle;
    }

    public Date getCourseStartDate() {
        return courseStartDate;
    }

    public void setCourseStartDate(Date courseStartDate) {
        this.courseStartDate = courseStartDate;
    }

    public Date getCourseFinishDate() {
        return courseFinishDate;
    }

    public void setCourseFinishDate(Date courseFinishDate) {
        this.courseFinishDate = courseFinishDate;
    }

    public Course getCourseService() {
        return courseService;
    }

    public void setCourseService(Course courseService) {
        this.courseService = courseService;
    }

    public int getHomeWorkMaxScore() {
        return homeWorkMaxScore;
    }

    public void setHomeWorkMaxScore(int homeWorkMaxScore) {
        this.homeWorkMaxScore = homeWorkMaxScore;
    }

    public int getStudentScore() {
        return studentScore;
    }

    public void setStudentScore(int studentScore) {
        this.studentScore = studentScore;
    }

    public boolean isDone() {
        return isDone;
    }

    public void setDone(boolean done) {
        isDone = done;
    }

    public List<CourseMaterialEntity> getMaterialTitles() {
        return materialTitles;
    }

    public void setMaterialTitles(List<CourseMaterialEntity> materialTitles) {
        this.materialTitles = materialTitles;
    }

    // Custom methods

    /**
     * Wrapper for fetch methods.
     */
    public void initCommonValues() {
        fetchCommonCourseInfo(courseId);
        fetchHWList(courseId);
        fetchCourseTitles();
    }

    /**
     * Fetch common course info for all possible actions.
     *
     * @param courseId                      Course ID.
     * @throws IllegalArgumentException     If course ID is null or less than 1.
     */
    protected void fetchCommonCourseInfo(Long courseId) throws IllegalArgumentException {
        logger.debug("fetchCommonCourseInfo() - started.");

        if (courseId == null || courseId < 1) {
            logger.error("Course ID can't be {}", courseId);
            logger.debug("fetchCourseInfo() - finished with IllegalArgumentException.");
            throw new IllegalArgumentException("Course ID can't be null or less than 1.");
        }

        logger.debug("Trying to fetch common course information for course with ID {}", courseId);
        CourseEntity courseInfo = courseService.getCourseById(courseId);
        if (courseInfo != null) {
            setCourseTitle(courseInfo.getTitle());
            setCourseFinishDate(courseInfo.getFinishDate());
            setCourseStartDate(courseInfo.getStartDate());
            logger.debug("Title: {}, Start date: {}, Finish date: {}", getCourseTitle(), getCourseStartDate(), getCourseFinishDate());
        } else {
            setCourseTitle("Not existent course");
            setCourseFinishDate(new Date());
            setCourseStartDate(new Date());
            logger.debug("Can't collect course info, setting values to their defaults.");
        }
        logger.debug("Final course Info: {}", courseInfo);

        logger.debug("fetchCommonCourseInfo() - finished.");
    }

    /**
     * Fetch HomeWork list for course with ID courseId.
     *
     * @param courseId                      Course ID.
     * @throws IllegalArgumentException     If course ID is null or less than 1.
     */
    protected void fetchHWList(Long courseId) throws IllegalArgumentException {
        logger.debug("fetchHWList() - started.");

        if (courseId == null || courseId < 1) {
            logger.error("Course ID can't be {}", courseId);
            logger.debug("fetchHWList() - finished with IllegalArgumentException.");
            throw new IllegalArgumentException("Course ID can't be null or less than 1.");
        }

        hwList = homeWorkService.getAllHomeworkByCourse(courseId);

        logger.debug("fetchHWList() - finished.");
    }

    /**
     * Fetch course material titles.
     */
    protected void fetchCourseTitles() {
        logger.debug("fetchCourseTitles() - started.");

        List<CourseMaterialEntity> materialTitles = null;
        try {
            logger.debug("Retrieve material titles for course with Id {}", courseId);
            materialTitles = materialService.getTitles(courseId);
            logger.debug("Material titles: {} ", materialTitles);
            if (materialTitles == null) {
                logger.debug("Material titles is null. Building empty List.");
                materialTitles = new ArrayList<>(1);
            }
        } catch (ServiceException e) {
            logger.error("Can't retrieve titles. Error message: {}, \nTrace:\n {}", e.getMessage(),
                    Arrays.deepToString(e.getStackTrace()));
            logger.debug("indexAction() catch ServiceException. Creating empty values.");
            materialTitles = new ArrayList<>(1);
        }

        setMaterialTitles(materialTitles);
        logger.debug("fetchCourseTitles - finished.");
    }

    /**
     * Generate i18n Map for template.
     *
     * @param parentMap         parent i18n Map.
     * @return                  Modified with local components Map.
     */
    protected Map<String, Object> getI18nMap(Map<String, Object> parentMap) {
        logger.debug("getI18nMap() - started.");

        logger.debug("Parent map {}", parentMap);
        ResourceBundle bundle = LocaleWrapper.getBundle("homework", locale);

        Map<String, Object> i18nHwMap = new HashMap<>();
        i18nHwMap.put("sidebar_header", bundle.getString("sidebar_header"));
        i18nHwMap.put("courseHome", bundle.getString("courseHome"));
        i18nHwMap.put("homework_a_label", bundle.getString("homework_a_label"));
        i18nHwMap.put("homework_expire_text", bundle.getString("homework_expire_text"));
        i18nHwMap.put("download_file_label", bundle.getString("download_file_label"));
        i18nHwMap.put("isDone_header", bundle.getString("isDone_header"));
        i18nHwMap.put("isNotDone_header", bundle.getString("isNotDone_header"));
        i18nHwMap.put("isExpired_header", bundle.getString("isExpired_header"));

        if (isDone) {
            MessageFormat formatter = new MessageFormat("");
            formatter.setLocale(locale);
            formatter.applyPattern(bundle.getString("isDone_text"));

            i18nHwMap.put("isDone_text", formatter.format(new Object[] {
                bundle.getString("isDone_text"),
                studentScore,
                homeWorkMaxScore}
            ));
        } else {
            if (new Date().after(homeWorkFinishDate)) {
                MessageFormat formatter = new MessageFormat("");
                formatter.setLocale(locale);
                formatter.applyPattern(bundle.getString("isExpired_text"));

                i18nHwMap.put("isExpired_text", formatter.format(new Object[] {
                        bundle.getString("isExpired_text"),
                        homeWorkFinishDate}
                ));
            } else {
                MessageFormat formatter = new MessageFormat("");
                formatter.setLocale(locale);
                formatter.applyPattern(bundle.getString("isNotDone_text"));

                i18nHwMap.put("isNotDone_text", formatter.format(new Object[] {
                    bundle.getString("isNotDone_text"),
                    homeWorkFinishDate}
                ));
            }
        }


        Map<String, Object> i18nMap = (parentMap == null)
                ? new HashMap<String, Object>()
                : parentMap;

        i18nMap.put("homework", i18nHwMap);
        Map<String, Object> i18nMaterialMap = new HashMap<>();
        i18nMaterialMap.put("syllabus", "");

        i18nMap.put("material", i18nMaterialMap);

        logger.debug("getI18nMap() - finished.");
        return i18nMap;
    }

}
